/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.workflow.service.usertask.impl;

import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.bpm.core.model.config.process.ProcessBasicConfigImpl;
import com.je.bpm.engine.ActivitiException;
import com.je.bpm.runtime.shared.RemoteCallServeManager;
import com.je.bpm.runtime.shared.dto.EventEarlyWarningDTO;
import com.je.bpm.runtime.shared.dto.EventSubmitDTO;
import com.je.common.auth.impl.RealOrganizationUser;
import com.je.common.auth.impl.account.Account;
import com.je.common.base.DynaBean;
import com.je.common.base.mapper.query.NativeQuery;
import com.je.common.base.result.BaseRespResult;
import com.je.common.base.service.MetaResourceService;
import com.je.common.base.service.MetaService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.ibatis.extension.plugins.pagination.Page;
import com.je.servicecomb.RpcSchemaFactory;
import com.je.workflow.model.OperatorEnum;
import com.je.workflow.rpc.dictionary.WorkFlowCustomBeanInvokeRpcService;
import com.je.workflow.rpc.dictionary.WorkFlowExecuteCustomMethodService;
import com.je.workflow.rpc.dictionary.WorkFlowRemoteCallServeManager;
import org.apache.servicecomb.common.rest.HttpTransportContext;
import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
import org.apache.servicecomb.foundation.vertx.http.StandardHttpServletRequestEx;
import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
import org.apache.servicecomb.swagger.invocation.context.ContextUtils;
import org.apache.servicecomb.swagger.invocation.context.InvocationContext;
import org.apache.servicecomb.swagger.invocation.context.TransportContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 流程流转调用远程服务实现
 */

@Service
public class RemoteCallServeManagerImpl implements RemoteCallServeManager {
    @Autowired
    private MetaResourceService metaResourceService;

    /**
     * 功能类型,视图
     */
    public static final String FUNC_VIEW = "VIEW";
    public static final String INSERT = "Insert";
    public static final String INSERT_AND_INIT = "InsertAndInit";
    public static final String DELETE = "Delete";
    public static final String UPDATE = "Update";
    public static final String SELECT = "Select";
    private static final Logger logger = LoggerFactory.getLogger(RemoteCallServeManagerImpl.class);

    public WorkFlowRemoteCallServeManager getService(String prod) {
        WorkFlowRemoteCallServeManager workFlowRemoteCallServeManager =
                RpcSchemaFactory.getRemoteProvierClazz(prod, "workFlowRemoteCallServeManager",
                        WorkFlowRemoteCallServeManager.class);
        return workFlowRemoteCallServeManager;
    }

    @Override
    public Object doGet(String prod, String id, String tableCode, Map<String, Object> customerParam) {
        logger.info("开始远程获取服务。。。。。。。。。。。。。。。");
        if (Strings.isNullOrEmpty(prod) || prod.equals("workflow")) {
            throw new ActivitiException("获取bean信息异常！");
        }
        WorkFlowRemoteCallServeManager workFlowRemoteCallServeManager = getService(prod);
        logger.info("结束远程获取服务。。。。。。。。。。。。。。。");
        return workFlowRemoteCallServeManager.doGetDynaBean(id, tableCode);
    }

    @Override
    public void doUpdate(Object bean, String id, ProcessBasicConfigImpl processBasicConfig, String prod, Map<String, Object> customerParam) {
        NativeQuery nativeQuery = NativeQuery.build();
        nativeQuery.tableCode("JE_CORE_FUNCINFO");
        nativeQuery.eq("JE_CORE_FUNCINFO_ID", processBasicConfig.getFuncId());
        List<DynaBean> list = metaResourceService.selectPageWithColumns("JE_CORE_FUNCINFO", new Page(-1, -1), nativeQuery, "");
        if (list.size() == 0) {
            return;
        }
        DynaBean dynaBean = list.get(0);
        prod = dynaBean.getStr("SY_PRODUCT_CODE");
        String type = dynaBean.getStr("FUNCINFO_FUNCTYPE");
        String tableCode = processBasicConfig.getTableCode();
        if (type.equals(FUNC_VIEW)) {
            tableCode = dynaBean.getStr("FUNCINFO_CRUDTABLENAME");
        }
        WorkFlowRemoteCallServeManager workFlowRemoteCallServeManager = getService(prod);
        workFlowRemoteCallServeManager.doUpdateBean(bean, id, tableCode);
    }

    @Override
    public void clearBusinessDataWorkFlowFiledInfo(String tableCode, String prod, String modelKey) {
        if (Strings.isNullOrEmpty(prod)) {
            return;
        }
        WorkFlowRemoteCallServeManager workFlowRemoteCallServeManager = getService(prod);
        workFlowRemoteCallServeManager.deployClearBusinessDataWorkFlowFiledInfo(tableCode, modelKey);
    }

    @Override
    public void executeCustomMethod(EventSubmitDTO eventSubmitDTO, String prod, String serviceName) {
        WorkFlowExecuteCustomMethodService workFlowExecuteCustomMethodService = null;
        try {
            workFlowExecuteCustomMethodService =
                    RpcSchemaFactory.getRemoteProvierClazz(prod, serviceName,
                            WorkFlowExecuteCustomMethodService.class);
        } catch (Exception e) {
            logger.error("无法找到指定的service");
            e.printStackTrace();
            throw new RuntimeException("无法找到指定的service");
        }

        try {
            com.je.workflow.model.EventSubmitDTO eventSubmit = new com.je.workflow.model.EventSubmitDTO();
            BeanUtils.copyProperties(eventSubmitDTO, eventSubmit);
            eventSubmit.setOperatorEnum(OperatorEnum.getOperatorEnumById(eventSubmitDTO.getOperatorEnum().toString()));
            workFlowExecuteCustomMethodService.executeCustomMethod(eventSubmit);
        } catch (Exception e) {
            logger.error("执行自定义方法异常！");
            e.printStackTrace();
            throw new RuntimeException("执行自定义方法异常！");
        }
    }

    @Override
    public void executeCustomMethod(String serviceName, String methodName, EventEarlyWarningDTO eventEarlyWarningDTO) {
        MetaService metaService = SpringContextHolder.getBean(MetaService.class);
        DynaBean dynaBean = metaService.selectOne("JE_WORKFLOW_PROCESSINFO",
                ConditionsWrapper.builder().eq("PROCESSINFO_KEY", eventEarlyWarningDTO.getWorkflowKey())
        );
        String prod = dynaBean.getStr("SY_PRODUCT_CODE");
        if (Strings.isNullOrEmpty(prod)) {
            throw new RuntimeException("执行自定义方法异常,产品标识没有找到！");
        }
        WorkFlowCustomBeanInvokeRpcService customBeanInvokeRpcService;
        customBeanInvokeRpcService = RpcSchemaFactory.getRemoteProvierClazz(prod, "workFlowCustomBeanInvokeRpcService",
                WorkFlowCustomBeanInvokeRpcService.class);

        com.je.workflow.model.EventEarlyWarningDTO copyDto = new com.je.workflow.model.EventEarlyWarningDTO();
        copyDto.setAssignee(eventEarlyWarningDTO.getAssignee()).setCurrentTaskName(eventEarlyWarningDTO.getCurrentTaskName())
                .setFuncCode(eventEarlyWarningDTO.getFuncCode()).setPkValue(eventEarlyWarningDTO.getPkValue())
                .setTaskId(eventEarlyWarningDTO.getTaskId()).setWorkflowKey(eventEarlyWarningDTO.getWorkflowKey())
                .setWorkflowName(eventEarlyWarningDTO.getWorkflowName()).setTableCode(eventEarlyWarningDTO.getTableCode());
        Object o = customBeanInvokeRpcService.invokeEventEarlyWarningCustomerMethod(serviceName, methodName, copyDto);
        if (o instanceof Boolean && (Boolean) o == true) {
            throw new RuntimeException("执行自定义方法异常！");
        }
    }


    @Override
    public void executeCustomSqlTemplate(String prod, String sqlTemplateCode, Map<String, Object> bean, String desc) {
        //模板编码不为空
        if (Strings.isNullOrEmpty(sqlTemplateCode)) {
            return;
        }
        List<DynaBean> dynaBeanList = metaResourceService.selectByNativeQuery(NativeQuery.build().tableCode("JE_CORE_QJSQL").eq("QJSQL_MBBM", sqlTemplateCode));
        String sqlProd = "";
        String templateContent = "";
        String executionStrategy = "";
        if (null != dynaBeanList && dynaBeanList.size() == 1) {
            sqlProd = String.valueOf(dynaBeanList.get(0).get("QJSQL_PROJECT_CODE"));
            templateContent = String.valueOf(dynaBeanList.get(0).get("QJSQL_MBNR"));
            executionStrategy = String.valueOf(dynaBeanList.get(0).get("QJSQL_SQLJBZXCL_CODE"));
        } else {
            logger.error(String.format("SQL模板执行异常！异常信息：" + "模板未找到，编码为【%s】", sqlTemplateCode));
            saveExceptionLog(String.format("SQL模板执行异常！异常信息：" + "模板未找到，编码为【%s】", sqlTemplateCode));
            throw new ActivitiException(String.format("SQL模板执行异常！异常信息：" + "模板未找到，编码为【%s】", sqlTemplateCode));
        }
        //模板所属产品，模板内容，执行策略 不为空
        if (Strings.isNullOrEmpty(sqlProd) || Strings.isNullOrEmpty(templateContent)
                || Strings.isNullOrEmpty(executionStrategy)) {
            return;
        }
        //根据不同的策略执行不同方法
        String url = "cse://" + sqlProd + "/je/common/script/sql%s";
        if (INSERT.equals(executionStrategy)) {
            url = String.format(url, "/insert");
        } else if (INSERT_AND_INIT.equals(executionStrategy)) {
            url = String.format(url, "/insertAndInit");
        } else if (DELETE.equals(executionStrategy)) {
            url = String.format(url, "/delete");
        } else if (UPDATE.equals(executionStrategy)) {
            url = String.format(url, "/update");
        } else if (SELECT.equals(executionStrategy)) {
            url = String.format(url, "/select");
        } else {
            return;
        }
        //调用具体服务，执行SQL模板
        executionTemplate(url, sqlProd, sqlTemplateCode, bean, desc);
    }

    @Override
    public String getProdByFuncCode(String funcCode) {
        NativeQuery query = NativeQuery.build();
        query.tableCode("JE_CORE_FUNCINFO");
        query.eq("FUNCINFO_FUNCCODE", funcCode);
        List<DynaBean> list = metaResourceService.selectByNativeQuery(query);
        if (list.size() == 0) {
            return "";
        }
        return list.get(0).getStr("SY_PRODUCT_CODE", "");
    }

    private void executionTemplate(String url, String sqlProd, String sqlTemplateCode, Map<String, Object> bean, String desc) {
        //通过servcieContext， 创建上下文
        //创建一个http请求
        //创建—个restTemplate
        InvocationContext invocationContext = ContextUtils.getInvocationContext();
        TransportContext transportContext = invocationContext.getTransportContext();
        HttpTransportContext httpTransportContext = (HttpTransportContext) transportContext;
        HttpServletRequest request = httpTransportContext.getRequestEx();
        HttpServletRequestEx requestEx = new StandardHttpServletRequestEx(request);
        RestTemplate restTemplate = RestTemplateBuilder.create();
        //设置参数
        url = url + "?templateCode=" + sqlTemplateCode + "&projectCode=" + sqlProd;

        //向全局上下文中设置bean信息
        logger.info("--------------------bean信息=" + bean.toString());
        JSONObject jsonObject = new JSONObject(bean);
        String encodeBean;
        try {
            encodeBean = URLEncoder.encode(jsonObject.toJSONString(), StandardCharsets.UTF_8.name());
            invocationContext.addContext("desc", URLEncoder.encode(desc, StandardCharsets.UTF_8.name()));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        logger.info("--------------------Context中的bean信息=" + encodeBean);
        invocationContext.addContext("workFlowBean", encodeBean);
        //发送请求
        BaseRespResult baseRespResult = restTemplate.postForObject(url,
                requestEx, BaseRespResult.class);
        logger.debug("模板执行结果：" + baseRespResult.getMessage());
        if (!baseRespResult.getSuccess()) {
            logger.error("SQL模板执行异常！异常信息：" + baseRespResult.getMessage());
            throw new ActivitiException("SQL模板执行异常！异常信息：" + baseRespResult.getMessage());
        }


    }

    public void saveExceptionLog(String message) {
        DynaBean setting = metaResourceService.selectOneByNativeQuery("JE_CORE_SETTING",
                NativeQuery.build().eq("CODE", "JE_SYS_LOGINFO"));
        logger.info("添加异常日志");
        if (setting != null) {
            String value = setting.getStr("VALUE");
            if (StringUtil.isEmpty(value) || (value.split(",").length == 0)) {
                return;
            }
            List<String> list = Arrays.asList(value.split(","));
            if (!list.contains("JE_SYS_EXCEPTIONLOG")) {
                return;
            }
        }
        try {
            DynaBean dynaBean = new DynaBean();
            dynaBean.table("JE_CORE_EXCEPTIONLOG");
            dynaBean.setStr("EXCEPTIONLOG_URL", "");
            dynaBean.setStr("EXCEPTIONLOG_MESSAGE", message);
            dynaBean.setStr("EXCEPTIONLOG_CODE", "9999");
            dynaBean.setStr("EXCEPTIONLOG_STACKTRACE", "");
            dynaBean.set("EXCEPTIONLOG_PARAMETER", "");
            dynaBean.put("SY_CREATETIME", DateUtils.formatDateTime(new Date()));
            Account account = SecurityUserHolder.getCurrentAccount();
            if (account != null) {
                RealOrganizationUser realOrganizationUser = account.getRealUser();
                if (realOrganizationUser != null) {
                    dynaBean.put("SY_CREATEUSERID", realOrganizationUser.getId());
                    dynaBean.put("SY_CREATEUSERNAME", realOrganizationUser.getName());
                }
            }
            metaResourceService.insert(dynaBean);
            logger.info("添加日志dynaBean=" + dynaBean.getValues().toString());
        } catch (Exception e) {
            logger.info("保存异常日志失败");
        }

    }

}
